﻿
/*============== simpleIRC - http://matthias.van-eeghem.com/ ==============*
 *                                                                         *
 *  File: MainWindow.xaml.cs                                               *
 *  Project: simpleIRC                                                     *
 *  Author(s): Matthias Van Eeghem <matthias@van-eeghem.com>               *
 *                                                                         *
 * ========================================================================*
 *                                                                         *
 *  This program is free software: you can redistribute it and/or modify   *
 *  it under the terms of the GNU General Public License as published by   *
 *  the Free Software Foundation, either version 3 of the License, or      *
 *  (at your option) any later version.                                    *
 *                                                                         *
 *  This program is distributed in the hope that it will be useful,        *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
 *  GNU General Public License for more details.                           *
 *                                                                         *
 *  You should have received a copy of the GNU General Public License      *
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
 *                                                                         *
===========================================================================*/

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Timers;

namespace simpleIRC.UI
{
    /// <summary>
    /// This is the MainWindow class, this is called when the application is launched.
    /// </summary>
     
    public partial class MainWindow : Window
    {
        #region The application variables
        /// <summary>
        /// This holds the index of the current channel window
        /// </summary>
        public int CurrentChannelWindow = -1;
        /// <summary>
        /// This holds the index of the current server window
        /// </summary>
        public int CurrentServerWindow = -1;
        /// <summary>
        /// This holds the index of the current query window
        /// </summary>
        internal int CurrentQueryWindow = -1;

        // Has the application started without any errors?
        private bool NoErrors = true;

        // If this variable is set to true the application will close without asking the user if he or she is still connected to a server.
        // This should only be set to true when the application has to update
        internal bool ForceClose = false;

        // These properties will hold the references to each of the class objects
        internal ConnectWindow ConnectWindow = null;
        internal CommandsWindow CommandsWindow = null;
        internal Command Command = null;
        internal EventListener EventListener = null;
        internal OptionsWindow OptionsWindow = null;
        internal UserInterface UserInterface = null;
        internal Colors Colors = null;
        internal Config Config = null;

        // The list containing the plugins
        internal List<PluginInterface> PluginList = new List<PluginInterface>();
        // The list containing the plugin names
        internal List<string> PluginNames = new List<string>();

        // This integer holds the current online time for the user in seconds
        long CurrentOnlineTime = 0;

        // The onlinetimer is kept at class-level so the garbage collection doesn't kill it
        Timer OnlineTimer = null;

        /// <summary>
        /// This enum holds all sort characters for the application. These sort characters are prepended to user's names in the Name property
        /// of each TreeViewItem in the UsersTreeView list. These are required so we can sort the TreeView on the Name property without resorting
        /// each level individually. We always want the owners on top alphabetically, superops below that alphabetically etc for the rest.
        /// </summary>

        public enum SortCharacters
        {
            /// <summary>
            /// The owner sort character
            /// </summary>
            OwnerCharacter = 'a',
            /// <summary>
            /// The superop sort character
            /// </summary>
            SuperOpCharacter = 'b',
            /// <summary>
            /// The operator sort character
            /// </summary>
            OpCharacter = 'c',
            /// <summary>
            /// The halfoperator sort character
            /// </summary>
            HalfopCharacter = 'd',
            /// <summary>
            /// The voice sort character
            /// </summary>
            VoiceCharacter = 'e',
            /// <summary>
            /// The character when you don't have any rights
            /// </summary>
            NoRightsCharacter = 'f'
        }

        #endregion

        /// <summary>
        /// The constructor of the class  
        /// </summary>

        public MainWindow()
        {
            InitializeComponent();

            // Let's first check if all required files and folders for this application are where they should be:
            string MissingFile = "";
            string[] Files = { "settings.xml", "Sounds/Bass.wav", "Sounds/Ping.wav", "Sounds/Pong.wav", "Sounds/Synth.wav" };

            // Check if all required files exist
            foreach(string FileName in Files)
            {
                if(!File.Exists(FileName))
                {
                    MissingFile = FileName;
                    NoErrors = false;
                }
            }

            // A file is missing, inform the user and close the application.
            if (NoErrors == false)
            {
                MessageBox.Show("simpleIRC could not be started because " + MissingFile + " is missing.\nPlease re-install this application to ensure all the files are located in the correct directory.", "Missing File", MessageBoxButton.OK, MessageBoxImage.Error);
                Close();
            }
            // Everything is in place, run the application.
            else
            {
                if (!Directory.Exists("Logs")) Directory.CreateDirectory("Logs");
                if (!Directory.Exists("Plugins")) Directory.CreateDirectory("Plugins");

                UserInterface = new UserInterface(this);
                Command = new Command(this);
                Colors = new Colors(this);
                EventListener = new EventListener(this);
                Config = new Config(this);

                OnlineTimer = new Timer();
                OnlineTimer.Elapsed += new ElapsedEventHandler(OnlineTimerTick);
                OnlineTimer.Interval = 1000;
                OnlineTimer.AutoReset = true;
                OnlineTimer.Start();

                // Initialise the Core class
                Core.Initialise();

                // Loop through all the .dll files in the directory
                foreach (string Filename in Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins"), "*.dll"))
                {
                    try
                    {
                        Assembly DllAssembly = Assembly.LoadFile(Filename);

                        foreach (Type AsmType in DllAssembly.GetTypes())
                        {
                             // Make sure it's the correct interface
                            if (AsmType.GetInterface("PluginInterface") != null)
                            {
                                // Create a new instance of the plugin
                                PluginInterface Plugin = (PluginInterface)Activator.CreateInstance(AsmType);
                                
                                // Get the index of the last \
                                int StartIndex = Filename.LastIndexOf('\\');

                                // Get the substring from the last index of the \ to the end
                                string FileWithoutDirectory = Filename.ToString().Substring(StartIndex + 1);

                                Plugin.OnBasePluginLoad(this);

                                PluginList.Add(Plugin);
                                PluginNames.Add(FileWithoutDirectory);
                            }
                        }
                    }

                    catch
                    {
                        MessageBox.Show("Failed to load " + Filename, "Failed to load plugin", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                }

                new Task(() => { new Update(this).CheckForUpdates(false); }).Start();
            }
        }

        /// <summary>
        /// This method is called every time the OnlineTimer ticks (meaning each second)
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>

        public void OnlineTimerTick(object source, ElapsedEventArgs e)
        {
            CurrentOnlineTime += 1;
        }

        /// <summary>
        /// Called when the user hits Connect in the Server tab.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void MenuStripFile_onConnectClick(object sender, RoutedEventArgs e)
        {
            // Only reconnect if the current window isn't connected
            if (CurrentServerWindow != -1 && Core.ServerList.Count > 0)
            {
                Server Server = Core.ServerList[CurrentServerWindow];

                if (Server.ConnectionState == Core.eConnectionStates.Disconnected)
                    Server.Connect();
            }
        }

        /// <summary>
        /// Called when the user hits New window in the Server tab.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void MenuStripFile_onNewWindowClick(object sender, RoutedEventArgs e)
        {
            // The form isn't open yet.
            if (ConnectWindow == null)
            {
                // Create a new instance of the ConnectWindow class.
                ConnectWindow = new ConnectWindow(this);
                ConnectWindow.Show();
            }
            // The form was already opened.
            else
            {
                // Simply set the focus.
                ConnectWindow.Focus();
            }
        }

        /// <summary>
        /// Called when the user hits the Treeview option in the View tab.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void MenuStripFile_onTreeviewClick(object sender, RoutedEventArgs e)
        {
            // If the treeview is visible, hide it
            if (ChannelsTreeView.Visibility == Visibility.Visible)
            {
                ChannelsTreeView.Visibility = Visibility.Hidden;
                ChannelsTreeView.Width = 0;
            }
            // Otherwise, make it visible
            else
            {
                ChannelsTreeView.Visibility = Visibility.Visible;
                ChannelsTreeView.Width = 130;
            }
        }

        /// <summary>
        /// Called when the user hits the Online Time option in the View tab.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void MenuStripFile_onOnlineTimeClick(object sender, RoutedEventArgs e)
        {
            TimeSpan CurrentTime = TimeSpan.FromSeconds(CurrentOnlineTime);
            TimeSpan TotalTime = TimeSpan.FromSeconds(Convert.ToInt64(Config.Settings["TotalOnlineTime"]));

            string Current = string.Format("{0:D2}:{1:D2}:{2:D2}", CurrentTime.Hours, CurrentTime.Minutes, CurrentTime.Seconds);
            string Total = string.Format("{0:D2}:{1:D2}:{2:D2}", TotalTime.Hours, TotalTime.Minutes, TotalTime.Seconds);
            MessageBox.Show("Your current online time: " + Current + "\nYour total online time: " + Total + "\n", "Your Online Time", MessageBoxButton.OK, MessageBoxImage.Information);
        }

        /// <summary>
        /// Called when the user hits the Userlist option in the View tab.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void MenuStripFile_onUserlistClick(object sender, RoutedEventArgs e)
        {
            if (CurrentChannelWindow != -1)
            {
                // If the treeview is visible, hide it
                if (UsersTreeView.Visibility == Visibility.Visible)
                {
                    UsersTreeView.Visibility = Visibility.Hidden;
                    UsersTreeView.Width = 0;
                }
                // Otherwise, make it visible
                else
                {
                    UsersTreeView.Visibility = Visibility.Visible;
                    UsersTreeView.Width = 100;
                }
            }
        }

        /// <summary>
        /// Called when the user hits Disconnect in the Server tab.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void MenuStripFile_onDisconnectClick(object sender, RoutedEventArgs e)
        {
            if (Core.ServerList.Count > 0)
            {
                Server Server = Core.ServerList[CurrentServerWindow];

                if (Server.ConnectionState > Core.eConnectionStates.Disconnected)
                {
                    Core.ServerList[CurrentServerWindow].Disconnect(Server.Nick, true);
                }
            }
        }

        /// <summary>
        /// Called when the user hits Exit in the Server tab.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void MenuStripFile_onExitClick(object sender, RoutedEventArgs e)
        {
            if (OptionsWindow != null) OptionsWindow.Close();
            if (CommandsWindow != null) CommandsWindow.Close();
            if (ConnectWindow != null) ConnectWindow.Close();

            Close();
        }

        /// <summary>
        /// Called when the user hits the Options tab in the menu tab.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void MenuStripFile_onShowOptions(object sender, RoutedEventArgs e)
        {
            // The form isn't open yet.
            if (OptionsWindow == null)
            {
                // Create a new instance of the OptionsWindow class.
                OptionsWindow = new OptionsWindow(this);
                OptionsWindow.Show();
            }
            // The form was already opened.
            else
            {
                // Simply set the focus.
                OptionsWindow.Focus();
            }
        }

        /// <summary>
        /// Called when the user hits the Options tab in the menu tab.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void MenuStripFile_onShowCommands(object sender, RoutedEventArgs e)
        {
            // The form isn't open yet.
            if (CommandsWindow == null)
            {
                // Create a new instance of the CommandsWindow class.
                CommandsWindow = new CommandsWindow(this);
                // And show the form.
                CommandsWindow.Show();
            }
            // The form was already opened.
            else
            {
                // Simply set the focus.
                CommandsWindow.Focus();
            }
        }

        /// <summary>
        /// Called when the user hits the Show Log Folder option in the Options tab
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void MenuStripFile_onShowLogFolder(object sender, RoutedEventArgs e)
        {
            System.Diagnostics.Process.Start(Directory.GetCurrentDirectory() + "\\Logs");
        }

        /// <summary>
        /// This function is called when the textbox was changed.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void ChatBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            // Scroll to the end of the textbox.
            ChatBox.ScrollToEnd();
        }

        /// <summary>
        /// Called when a key is pressed on the main form.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        
        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                // We don't want to send an empty output.
                if(SendBox.GetLineLength(0) > 0)
                {
                    // The first character is a slash, this means he typed a command.
                    if (SendBox.Text[0] == '/')
                    {
                        // Handle the command with the Command class.
                        Command.Handle(SendBox.Text);
                        foreach (PluginInterface Plugin in PluginList) if (Plugin != null) Plugin.OnCommandEntered(SendBox.Text);
                    }
                    // He didn't use a command, send the output text to the current channel he's typing in.
                    else
                    {
                        // The user tried to send a message to the server
                        if (CurrentQueryWindow == -1 && CurrentChannelWindow == -1)
                        {
                            ServerWindow.List[CurrentServerWindow].SendText("* You are not on a channel\r");
                        }

                        // A channel
                        else if (CurrentQueryWindow == -1 && CurrentChannelWindow != -1)
                        {
                            Server Server = Core.ServerList[CurrentServerWindow];
                            Channel Channel = Core.ChannelList[CurrentChannelWindow];

                            if (Server.ConnectionState == Core.eConnectionStates.Disconnected)
                            {
                                ChannelWindow.List[Channel.Index].SendText("* You're not connected to this server.\r");
                            }
                            else
                            {
                                Server.SendData("PRIVMSG " + Channel.Name + " :" + SendBox.Text);

                                string Output = "<" + Channel.GetUserHighestRights(Server.Nick) + Server.Nick + "> " + SendBox.Text + "\r";
                                ChannelWindow.List[Channel.Index].SendText(Output);
                                Core.GetChannelObject(Channel.Name, CurrentServerWindow).Logger.Log(Output);
                            }
                        }

                        // A private message
                        else
                        {
                            if (Core.ServerList.Count > CurrentServerWindow)
                            {
                                Server Server = Core.ServerList[CurrentServerWindow];

                                if (Server.ConnectionState == Core.eConnectionStates.Connected)
                                {
                                    Query Query = Core.QueryList[CurrentQueryWindow];

                                    // Send the command to the server.
                                    Server.SendData("PRIVMSG " + Query.Name + " :" + SendBox.Text);

                                    string Output = "<" + Server.Nick + "> " + SendBox.Text + "\r";
                                    Query.Logger.Log(Output);
                                    QueryWindow.List[CurrentQueryWindow].SendText(Output);
                                }
                            }
                        }
                    }

                    SendBox.Clear();
                }
            }
        }

        /// <summary>
        /// Called when the main form is closed.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            // Only execute this code if the application actually started without errors
            if (NoErrors)
            {
                int ServerCount = Core.ServerList.Count;

                // Save whether the UsersTreeView is visible or not
                if (UsersTreeView.Visibility == Visibility.Visible)
                {
                    Config.SetConfigValue("UserListVisible", "true");
                }
                else
                {
                    Config.SetConfigValue("UserListVisible", "false");
                }

                // Save whether the ChannelsTreeView is visible or not
                if(ChannelsTreeView.Visibility == Visibility.Visible)
                {
                    Config.SetConfigValue("ChannelListVisible", "true");
                }
                else
                {
                    Config.SetConfigValue("ChannelListVisible", "false");
                }

                // Save the total online time
                long TotalTime = CurrentOnlineTime + Convert.ToInt64(Config.Settings["TotalOnlineTime"]);
                Config.SetConfigValue("TotalOnlineTime", TotalTime.ToString());

                // We now check if we're connected to any server at all
                bool isConnected = false;

                for (int i = 0; i < ServerCount; i++)
                {
                    // Make sure the server isn't null
                    if (Core.ServerList[i] == null) continue;

                    // If any server is connected, set the isConnected bool to true and break out of the loop
                    if (Core.ServerList[i].ConnectionState > Core.eConnectionStates.Disconnected)
                    {
                        isConnected = true;
                        break;
                    }
                }

                // If we're connected to one or more servers, inform the user!
                if (isConnected)
                {
                    if (ForceClose)
                    {
                        // Call the OnApplicationClosing event
                        foreach (PluginInterface Plugin in PluginList) if (Plugin != null) Plugin.OnApplicationClosing();

                        Core.Destruct();
                        e.Cancel = false;
                    }
                    else
                    {
                        MessageBoxResult CloseDialog = MessageBox.Show("You are still connected to one ore more IRC servers! Are you sure you wish to quit?", "Confirm Exit", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.Yes);

                        // He wants to close the application, disconnect all servers first though.
                        if (CloseDialog == MessageBoxResult.Yes)
                        {
                            // Call the OnApplicationClosing event
                            foreach (PluginInterface Plugin in PluginList) if (Plugin != null) Plugin.OnApplicationClosing();

                            Core.Destruct();
                            e.Cancel = false;
                        }

                        // He doesn't want to close the application, cancel the event
                        else e.Cancel = true;
                    }
                }
                else foreach (PluginInterface Plugin in PluginList) if (Plugin != null) Plugin.OnApplicationClosing();
            }
        }

        /// <summary>
        /// Called when a user double clicks a name in the treeviewlist.
        /// It calls the ContextMenu_QueryUser method.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void UsersTreeView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (UsersTreeView.SelectedItem != null)
            {
                UserInterface.ContextMenu_QueryUser(null, null);
            }
        }

        /// <summary>
        /// Called when the user right clicks a TreeViewItem
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void UsersTreeView_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            TreeViewItem SelectedItem = new TreeViewItem();
            SelectedItem = UsersTreeView.SelectedItem as TreeViewItem;

            // Check if we have an item selected and check if we've already added the subitems
            if (SelectedItem != null && SelectedItem.ContextMenu == null)
            {
                MenuItem InfoItem = new MenuItem();
                InfoItem.Header = "Info";

                MenuItem QueryUser = new MenuItem();
                QueryUser.Header = "PM";
                QueryUser.Click += new RoutedEventHandler(UserInterface.ContextMenu_QueryUser);

                // All of the subitems for the QueryUser MenuItem
                MenuItem PingItem = new MenuItem();
                PingItem.Header = "Ping";
                PingItem.Click += new RoutedEventHandler(UserInterface.ContextMenu_Info_Ping);

                MenuItem TimeItem = new MenuItem();
                TimeItem.Header = "Time";
                TimeItem.Click += new RoutedEventHandler(UserInterface.ContextMenu_Info_Time);

                MenuItem VersionItem = new MenuItem();
                VersionItem.Header = "Version";
                VersionItem.Click += new RoutedEventHandler(UserInterface.ContextMenu_Info_Version);

                MenuItem WhoisItem = new MenuItem();
                WhoisItem.Header = "Whois";
                WhoisItem.Click += new RoutedEventHandler(UserInterface.ContextMenu_Info_Whois);
                // End of the subitems list

                MenuItem Level = new MenuItem();
                Level.Header = "Level";

                // All of the subitems for the Level MenuItem
                MenuItem VoiceItem = new MenuItem();
                VoiceItem.Header = "Voice (+)";
                VoiceItem.Click += new RoutedEventHandler(UserInterface.ContextMenu_Level_Voice);

                MenuItem DevoiceItem = new MenuItem();
                DevoiceItem.Header = "Devoice (+)";
                DevoiceItem.Click += new RoutedEventHandler(UserInterface.ContextMenu_Level_Devoice);

                MenuItem HalfopItem = new MenuItem();
                HalfopItem.Header = "Halfop (%)";
                HalfopItem.Click += new RoutedEventHandler(UserInterface.ContextMenu_Level_Halfop);

                MenuItem DehalfopItem = new MenuItem();
                DehalfopItem.Header = "Dehalfop (%)";
                DehalfopItem.Click += new RoutedEventHandler(UserInterface.ContextMenu_Level_Dehalfop);

                MenuItem OpItem = new MenuItem();
                OpItem.Header = "Op (@)";
                OpItem.Click += new RoutedEventHandler(UserInterface.ContextMenu_Level_Op);

                MenuItem DeopItem = new MenuItem();
                DeopItem.Header = "Deop (@)";
                DeopItem.Click += new RoutedEventHandler(UserInterface.ContextMenu_Level_Deop);

                MenuItem SuperopItem = new MenuItem();
                SuperopItem.Header = "Superop (&)";
                SuperopItem.Click += new RoutedEventHandler(UserInterface.ContextMenu_Level_Superop);

                MenuItem DesuperopItem = new MenuItem();
                DesuperopItem.Header = "Desuperop (&)";
                DesuperopItem.Click += new RoutedEventHandler(UserInterface.ContextMenu_Level_Desuperop);

                MenuItem OwnerItem = new MenuItem();
                OwnerItem.Header = "Owner (~)";
                OwnerItem.Click += new RoutedEventHandler(UserInterface.ContextMenu_Level_Owner);

                MenuItem DeownerItem = new MenuItem();
                DeownerItem.Header = "Deowner (~)";
                DeownerItem.Click += new RoutedEventHandler(UserInterface.ContextMenu_Level_Deowner);
                // End of the subitems list

                ContextMenu RightClickMenu = new ContextMenu();
                SelectedItem.ContextMenu = RightClickMenu;
                SelectedItem.ContextMenu.Items.Add(QueryUser);

                InfoItem.Items.Add(PingItem);
                InfoItem.Items.Add(TimeItem);
                InfoItem.Items.Add(VersionItem);
                InfoItem.Items.Add(WhoisItem);

                SelectedItem.ContextMenu.Items.Add(InfoItem);

                Level.Items.Add(VoiceItem);
                Level.Items.Add(DevoiceItem);
                Level.Items.Add(HalfopItem);
                Level.Items.Add(DehalfopItem);
                Level.Items.Add(OpItem);
                Level.Items.Add(DeopItem);
                Level.Items.Add(SuperopItem);
                Level.Items.Add(DesuperopItem);
                Level.Items.Add(OwnerItem);
                Level.Items.Add(DeownerItem);

                SelectedItem.ContextMenu.Items.Add(Level);
            }
        }

        /// <summary>
        /// Called when the user hits an item in the channeltreeview list.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        
        public void ChannelsTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            ChatBox.Document.Blocks.Clear();

            TreeViewItem SelectedItem = ChannelsTreeView.SelectedItem as TreeViewItem;

            if (SelectedItem != null)
            {
                TreeViewItem ParentItem = ParentItem = SelectedItem.Parent as TreeViewItem;

                // If the parent item isn't null, the user selected a channel window.
                if (ParentItem != null)
                {
                    string ItemName = SelectedItem.Header.ToString();
                    string ServerName = ParentItem.Name.ToString();

                    // Check if the list selected was a query
                    if (ParentItem.Header.ToString().IndexOf("Query", 0, 5) != -1)
                    {
                        if (UsersTreeView.Width == 100) UsersTreeView.Width = 0;

                        Server Server = Core.GetServerObject(ServerName);
                        Query Query = Core.GetQueryObject(ItemName, Server.Index);

                        if(Query != null)
                        {
                            CurrentChannelWindow = -1;
                            CurrentQueryWindow = Query.Index;
                            CurrentServerWindow = Server.Index;

                            if (QueryWindow.List[Query.Index].QueryTreeViewItem.Foreground != Brushes.Black) QueryWindow.List[Query.Index].QueryTreeViewItem.Foreground = Brushes.Black;

                            // And show the new text.
                            new Task(() => { Colors.HandleColors(Core.QueryList[Query.Index].Text); }).Start();
                        }
                    }
                    else
                    {
                        if (UsersTreeView.Width == 0) UsersTreeView.Width = 100;
                        UsersTreeView.Items.Clear();

                        // Get the channel and server index.
                        Server Server = Core.GetServerObject(ServerName);
                        Channel Channel = Core.GetChannelObject(ItemName, Server.Index);

                        if(Channel != null)
                        {
                            CurrentServerWindow = Server.Index;
                            CurrentChannelWindow = Channel.Index;
                            CurrentQueryWindow = -1;

                            if (ChannelWindow.List[Channel.Index].ChannelTreeViewItem.Foreground != Brushes.Black) ChannelWindow.List[Channel.Index].ChannelTreeViewItem.Foreground = Brushes.Black;

                            new Task(() =>
                            {
                                Colors.HandleColors(Channel.Text);
                                ChannelWindow.List[Channel.Index].LoadUsers();
                            }).Start();
                        }
                    }
                }

                // The user selected a server window.
                else
                {
                    // Hide the usertreeview if it's a server.
                    if (UsersTreeView.Width == 100) UsersTreeView.Width = 0;

                    // Get the server name.
                    string ServerName = SelectedItem.Name.ToString();
                    Server Server = Core.GetServerObject(ServerName);

                    if (Server != null)
                    {
                        CurrentChannelWindow = -1;
                        CurrentQueryWindow = -1;
                        CurrentServerWindow = Server.Index;

                        if (ServerWindow.List[Server.Index].ServerTreeViewItem.Foreground != Brushes.Black) ServerWindow.List[Server.Index].ServerTreeViewItem.Foreground = Brushes.Black;
                        new Task(() => { Colors.HandleColors(Core.ServerList[Server.Index].Text); }).Start();
                    }
                }
            }
        }
    }
}